home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1 / win / x11 / winmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-16  |  27.9 KB  |  1,036 lines

  1. /*    SCCS Id: @(#)winmap.c    3.1    92/04/30          */
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * This file contains:
  7.  *    + global functions print_glyph() and cliparound()
  8.  *     + the map window routines
  9.  *    + the char and pointer input routines
  10.  *
  11.  * Notes:
  12.  *    + We don't really have a good way to get the compiled ROWNO and 
  13.  *      COLNO as defaults.  They are hardwired to the current "correct"
  14.  *      values in the Window widget.  I am _not_ in favor of including
  15.  *      some nethack include file for Window.c.
  16.  */
  17. #include <X11/Intrinsic.h>
  18. #include <X11/StringDefs.h>
  19. #include <X11/Shell.h>
  20. #include <X11/Xaw/Cardinals.h>
  21. #include <X11/Xaw/Scrollbar.h>
  22. #include <X11/Xaw/Viewport.h>
  23. #include "Window.h"    /* map widget declarations */
  24.  
  25. #include "hack.h"
  26. #include "winX.h"
  27.  
  28. /* Define these if you really want a lot of junk on your screen. */
  29. /* #define VERBOSE        /* print various info & events as they happen */
  30. /* #define VERBOSE_UPDATE    /* print screen update bounds */
  31. /* #define VERBOSE_INPUT    /* print input events */
  32.  
  33. static void set_button_values();
  34. static void map_check_size_change();
  35. static void map_update();
  36. static void map_exposed();
  37. static void map_input();
  38. static void set_gc();
  39. static void get_gc();
  40. static void get_char_info();
  41. static void display_cursor();
  42.  
  43. /* Global functions ======================================================== */
  44.  
  45. void
  46. X11_print_glyph(window, x, y, glyph)
  47.     winid window;
  48.     xchar x, y;
  49.     int glyph;
  50. {
  51.     uchar          ch;
  52.     register int      offset;
  53.     struct map_info_t *map_info;
  54.     register unsigned char *ch_ptr;
  55. #ifdef TEXTCOLOR
  56.     int     color;
  57.     register unsigned char *co_ptr;
  58.  
  59. #define zap_color(n)  color = zapcolors[n]
  60. #define cmap_color(n) color = defsyms[n].color
  61. #define trap_color(n) color = (n == WEB) ? defsyms[S_web ].color : \
  62.                        defsyms[S_trap].color
  63. #define obj_color(n)  color = objects[n].oc_color
  64. #define mon_color(n)  color = mons[n].mcolor
  65. #define pet_color(n)  color = mons[n].mcolor
  66.  
  67. # else /* no text color */
  68.  
  69. #define zap_color(n)
  70. #define cmap_color(n)
  71. #define trap_color(n)
  72. #define obj_color(n)
  73. #define mon_color(n)
  74. #define pet_color(n)
  75. #endif
  76.  
  77.     check_winid(window);
  78.     if (window_list[window].type != NHW_MAP) {
  79.     impossible("print_glyph: can (currently) only print to map windows");
  80.     return;
  81.     }
  82.     map_info = window_list[window].map_information;
  83.  
  84.     /*
  85.      *  Map the glyph back to a character.
  86.      *
  87.      *  Warning:  For speed, this makes an assumption on the order of
  88.      *            offsets.  The order is set in display.h.
  89.      */
  90.     if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {        /* swallow */
  91.     /* see swallow_to_glyph() in display.c */
  92.     ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
  93.     mon_color(offset >> 3);
  94.     } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {    /* zap beam */
  95.     /* see zapdir_to_glyph() in display.c */
  96.     ch = showsyms[S_vbeam + (offset & 0x3)];
  97.     zap_color((offset >> 2));
  98.     } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) {    /* cmap */
  99.     ch = showsyms[offset];
  100.     cmap_color(offset);
  101.     } else if ((offset = (glyph - GLYPH_TRAP_OFF)) >= 0) {    /* trap */
  102.     ch = (offset == WEB) ? showsyms[S_web] : showsyms[S_trap];
  103.     trap_color(offset);
  104.     } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) {    /* object */
  105.     ch = oc_syms[objects[offset].oc_class];
  106.     obj_color(offset);
  107.     } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {    /* a corpse */
  108.     ch = oc_syms[objects[CORPSE].oc_class];
  109.     mon_color(offset);
  110.     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {    /* a pet */
  111.     ch = monsyms[mons[offset].mlet];
  112.     pet_color(offset);
  113.     } else {                            /* a monster */
  114.     ch = monsyms[mons[glyph].mlet];
  115.     mon_color(glyph);
  116.     }
  117.  
  118.     /* Only update if we need to. */
  119.     ch_ptr = &map_info->text[y][x];
  120.  
  121. #ifdef TEXTCOLOR
  122.     co_ptr = &map_info->colors[y][x];
  123.     if (*ch_ptr != ch || *co_ptr != color)
  124. #else
  125.     if (*ch_ptr != ch)
  126. #endif
  127.     {
  128.     *ch_ptr = ch;
  129. #ifdef TEXTCOLOR
  130.     *co_ptr = color;
  131. #endif
  132.     /* update row bbox */
  133.     if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x;
  134.     if ((uchar) x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
  135.     }
  136.  
  137. #undef zap_color
  138. #undef cmap_color
  139. #undef trap_color
  140. #undef obj_color
  141. #undef mon_color
  142. #undef pet_color
  143. }
  144.  
  145. #ifdef CLIPPING
  146. /*
  147.  * The is the tty clip call.  Since X can resize at any time, we can't depend
  148.  * on this being defined.
  149.  */
  150. /*ARGSUSED*/
  151. void X11_cliparound(x, y) int x, y; { }
  152. #endif /* CLIPPING */
  153.  
  154. /* End global functions ==================================================== */
  155.  
  156.  
  157. /*
  158.  * Make sure the map's cursor is always visible.
  159.  */
  160. void
  161. check_cursor_visibility(wp)
  162.     struct xwindow *wp;
  163. {
  164.     Arg arg[2];
  165.     Widget viewport, horiz_sb, vert_sb;
  166.     float top, shown, cursor_middle;
  167.     Boolean do_call, adjusted = False;
  168. #ifdef VERBOSE
  169.     char *s;
  170. #endif
  171.  
  172.     viewport = XtParent(wp->w);
  173.     horiz_sb = XtNameToWidget(viewport, "horizontal");
  174.     vert_sb  = XtNameToWidget(viewport, "vertical");
  175.  
  176. #define V_BORDER 0.1        /* if this far from vert edge, shift */
  177. #define H_BORDER 0.0625        /* if this from from horiz edge, shift */
  178.  
  179. #define H_DELTA 0.25        /* distance of horiz shift */
  180.                 /* vert shift is half of curr distance */
  181. /* The V_DELTA is 1/2 the value of shown. */
  182.  
  183.     if (horiz_sb) {
  184.     XtSetArg(arg[0], XtNshown,    &shown);
  185.     XtSetArg(arg[1], XtNtopOfThumb, &top);
  186.     XtGetValues(horiz_sb, arg, TWO);
  187.  
  188.     cursor_middle = (((float) wp->cursx) + 0.5) / (float) COLNO;
  189.     do_call = True;
  190.  
  191. #ifdef VERBOSE
  192.     if (cursor_middle < top) {
  193.         s = " outside left";
  194.     } else if (cursor_middle < top + H_BORDER) {
  195.         s = " close to left";
  196.     } else if (cursor_middle > (top + shown)) {
  197.         s = " outside right";
  198.     } else if (cursor_middle > (top + shown - H_BORDER)) {
  199.         s = " close to right";
  200.     } else {
  201.         s = "";
  202.     }
  203.     printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s);
  204. #endif
  205.  
  206.     if (cursor_middle < top) {
  207.         top = cursor_middle - H_DELTA;
  208.         if (top < 0.0) top = 0;
  209.     } else if (cursor_middle < top + H_BORDER) {
  210.         top -= H_DELTA;
  211.         if (top < 0.0) top = 0.0;
  212.     } else if (cursor_middle > (top + shown)) {
  213.         top = cursor_middle + H_DELTA;
  214.         if (top + shown > 1.0) top = 1.0 - shown;
  215.     } else if (cursor_middle > (top + shown - H_BORDER)) {
  216.         top += H_DELTA;
  217.         if (top + shown > 1.0) top = 1.0 - shown;
  218.     } else {
  219.         do_call = False;
  220.     }
  221.  
  222.     if (do_call) {
  223.         XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
  224.         adjusted = True;
  225.     }
  226.     }
  227.  
  228.     if (vert_sb) {
  229.     XtSetArg(arg[0], XtNshown,      &shown);
  230.     XtSetArg(arg[1], XtNtopOfThumb, &top);
  231.     XtGetValues(vert_sb, arg, TWO);
  232.  
  233.     cursor_middle = (((float) wp->cursy) + 0.5) / (float) ROWNO;
  234.     do_call = True;
  235.  
  236. #ifdef VERBOSE
  237.     if (cursor_middle < top) {
  238.         s = " above top";
  239.     } else if (cursor_middle < top + V_BORDER) {
  240.         s = " close to top";
  241.     } else if (cursor_middle > (top + shown)) {
  242.         s = " below bottom";
  243.     } else if (cursor_middle > (top + shown - V_BORDER)) {
  244.         s = " close to bottom";
  245.     } else {
  246.         s = "";
  247.     }
  248.     printf("%sVert: shown = %3.2f, top = %3.2f%s",
  249.                     horiz_sb ? ";  " : "", shown, top, s);
  250. #endif
  251.  
  252.     if (cursor_middle < top) {
  253.         top = cursor_middle - (shown / 2.0);
  254.         if (top < 0.0) top = 0;
  255.     } else if (cursor_middle < top + V_BORDER) {
  256.         top -= shown / 2.0;
  257.         if (top < 0.0) top = 0;
  258.     } else if (cursor_middle > (top + shown)) {
  259.         top = cursor_middle - (shown / 2.0);
  260.         if (top < 0.0) top = 0;
  261.         if (top + shown > 1.0) top = 1.0 - shown;
  262.     } else if (cursor_middle > (top + shown - V_BORDER)) {
  263.         top += shown / 2.0;
  264.         if (top + shown > 1.0) top = 1.0 - shown;
  265.     } else {
  266.         do_call = False;
  267.     }
  268.  
  269.     if (do_call) {
  270.         XtCallCallbacks(vert_sb, XtNjumpProc, &top);
  271.         adjusted = True;
  272.     }
  273.     }
  274.  
  275.     /* make sure cursor is displayed during dowhatis.. */
  276.     if (adjusted) display_cursor(wp);
  277.  
  278. #ifdef VERBOSE
  279.     if (horiz_sb || vert_sb) printf("\n");
  280. #endif
  281. }
  282.  
  283.  
  284. /*
  285.  * Check to see if the viewport has grown smaller.  If so, then we want to make
  286.  * sure that the cursor is still on the screen.  We do this to keep the cursor
  287.  * on the screen when the user resizes the nethack window.
  288.  */
  289. static void
  290. map_check_size_change(wp)
  291.     struct xwindow *wp;
  292. {
  293.     struct map_info_t *map_info = wp->map_information;
  294.     Arg arg[2];
  295.     Dimension new_width, new_height;
  296.     Widget viewport;
  297.  
  298.     viewport = XtParent(wp->w);
  299.  
  300.     XtSetArg(arg[0], XtNwidth,  &new_width);
  301.     XtSetArg(arg[1], XtNheight, &new_height);
  302.     XtGetValues(viewport, arg, TWO);
  303.  
  304.     /* Only do cursor check if new size is smaller. */
  305.     if (new_width < map_info->viewport_width
  306.             || new_height < map_info->viewport_height) {
  307.     check_cursor_visibility(wp);
  308.     }
  309.  
  310.     map_info->viewport_width = new_width;
  311.     map_info->viewport_height = new_height;
  312. }
  313.  
  314. /*
  315.  * Fill in parameters "regular" and "inverse" with newly created GCs.
  316.  * Using the given background pixel and the foreground pixel optained
  317.  * by querying the widget with the resource name.
  318.  */
  319. static void
  320. set_gc(w, font, resource_name, bgpixel, regular, inverse)
  321.     Widget w;
  322.     Font font;
  323.     char *resource_name;
  324.     Pixel bgpixel;
  325.     GC   *regular, *inverse;
  326. {
  327.     XGCValues values;
  328.     XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
  329.     Pixel curpixel;
  330.     Arg arg[1];
  331.  
  332.     XtSetArg(arg[0], resource_name, &curpixel);
  333.     XtGetValues(w, arg, ONE);
  334.  
  335.     values.foreground = curpixel;
  336.     values.background = bgpixel;
  337.     values.function   = GXcopy;
  338.     values.font          = font;
  339.     *regular = XtGetGC(w, mask, &values);
  340.     values.foreground = bgpixel;
  341.     values.background = curpixel;
  342.     values.function   = GXcopy;
  343.     values.font          = font;
  344.     *inverse = XtGetGC(w, mask, &values);
  345. }
  346.  
  347. /*
  348.  * Create the GC's for each color.
  349.  *
  350.  * I'm not sure if it is a good idea to have a GC for each color (and
  351.  * inverse). It might be faster to just modify the foreground and
  352.  * background colors on the current GC as needed.
  353.  */
  354. static void
  355. get_gc(wp, font)
  356.     struct xwindow *wp;
  357.     Font font;
  358. {
  359.     struct map_info_t *map_info = wp->map_information;
  360.     Pixel bgpixel;
  361.     Arg arg[1];
  362.  
  363.     /* Get background pixel. */
  364.     XtSetArg(arg[0], XtNbackground, &bgpixel);
  365.     XtGetValues(wp->w, arg, ONE);
  366.  
  367. #ifdef TEXTCOLOR
  368. #define set_color_gc(nh_color, resource_name)            \
  369.         set_gc(wp->w, font, resource_name, bgpixel,        \
  370.             &map_info->color_gcs[nh_color],        \
  371.             &map_info->inv_color_gcs[nh_color]);
  372.  
  373.     set_color_gc(BLACK,         XtNblack);
  374.     set_color_gc(RED,         XtNred);
  375.     set_color_gc(GREEN,         XtNgreen);
  376.     set_color_gc(BROWN,         XtNbrown);
  377.     set_color_gc(BLUE,         XtNblue);
  378.     set_color_gc(MAGENTA,     XtNmagenta);
  379.     set_color_gc(CYAN,         XtNcyan);
  380.     set_color_gc(GRAY,         XtNgray);
  381.     set_color_gc(NO_COLOR,     XtNforeground);
  382.     set_color_gc(ORANGE_COLORED, XtNorange);
  383.     set_color_gc(BRIGHT_GREEN,     XtNbright_green);
  384.     set_color_gc(YELLOW,     XtNyellow);
  385.     set_color_gc(BRIGHT_BLUE,     XtNbright_blue);
  386.     set_color_gc(BRIGHT_MAGENTA, XtNbright_magenta);
  387.     set_color_gc(BRIGHT_CYAN,     XtNbright_cyan);
  388.     set_color_gc(WHITE,         XtNwhite);
  389. #else
  390.     set_gc(wp->w, font, XtNforeground, bgpixel,
  391.                 &map_info->copy_gc, &map_info->inv_copy_gc);
  392. #endif
  393. }
  394.  
  395.  
  396. /*
  397.  * Display the cursor on the map window.
  398.  */
  399. static void
  400. display_cursor(wp)
  401.     struct xwindow *wp;
  402. {
  403.     /* Redisplay the cursor location inverted. */
  404.     map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE);
  405. }
  406.  
  407.  
  408. /*
  409.  * Check if there are any changed characters.  If so, then plaster them on
  410.  * the screen.
  411.  */
  412. void
  413. display_map_window(wp)
  414.     struct xwindow *wp;
  415. {
  416.     register int row;
  417.     struct map_info_t *map_info = wp->map_information;
  418.  
  419.     /*
  420.      * If the previous cursor position is not the same as the current
  421.      * cursor position, then update the old cursor position.
  422.      */
  423.     if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) {
  424.     register unsigned int x = wp->prevx, y = wp->prevy;
  425.     if (x < map_info->t_start[y]) map_info->t_start[y] = x;
  426.     if (x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
  427.     }
  428.  
  429.     for (row = 0; row < ROWNO; row++) {
  430.     if (map_info->t_start[row] <= map_info->t_stop[row]) {
  431.         map_update(wp, row, row,
  432.             (int) map_info->t_start[row],
  433.             (int) map_info->t_stop[row], FALSE);
  434.         map_info->t_start[row] = COLNO-1;
  435.         map_info->t_stop[row] = 0;
  436.     }
  437.     }
  438.     display_cursor(wp);
  439.     wp->prevx = wp->cursx;    /* adjust old cursor position */
  440.     wp->prevy = wp->cursy;
  441. }
  442.  
  443. /*
  444.  * Fill the saved screen characters with the "clear" character, and reset
  445.  * all colors to the neutral color.  Flush out everything by resetting the
  446.  * "new" bounds and calling display_map_window().
  447.  */
  448. void
  449. clear_map_window(wp)
  450.     struct xwindow *wp;
  451. {
  452.     struct map_info_t *map_info = wp->map_information;
  453.  
  454.     /* Fill with spaces, and update */
  455.     (void) memset((genericptr_t) map_info->text, ' ',
  456.             sizeof(map_info->text));
  457.     (void) memset((genericptr_t) map_info->t_start, (char) 0,
  458.             sizeof(map_info->t_start));
  459.     (void) memset((genericptr_t) map_info->t_stop, (char) COLNO-1,
  460.             sizeof(map_info->t_stop));
  461. #ifdef TEXTCOLOR
  462.     (void) memset((genericptr_t) map_info->colors, NO_COLOR,
  463.             sizeof(map_info->colors));
  464. #endif
  465.     display_map_window(wp);
  466. }
  467.  
  468. /*
  469.  * Retreive the font associated with the map window and save attributes
  470.  * that are used when updating it.
  471.  */
  472. static void
  473. get_char_info(wp)
  474.     struct xwindow *wp;
  475. {
  476.     XFontStruct *fs;
  477.  
  478.     fs = WindowFontStruct(wp->w);
  479.     wp->map_information->char_width    = fs->max_bounds.width;
  480.     wp->map_information->char_height   = fs->max_bounds.ascent +
  481.                         fs->max_bounds.descent;
  482.     wp->map_information->char_ascent   = fs->max_bounds.ascent;
  483.     wp->map_information->char_lbearing = -fs->min_bounds.lbearing;
  484.  
  485. #ifdef VERBOSE
  486.     printf("Font information:\n");
  487.     printf("fid = %d, direction = %d\n", fs->fid, fs->direction);
  488.     printf("first = %d, last = %d\n",
  489.             fs->min_char_or_byte2, fs->max_char_or_byte2);
  490.     printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no");
  491.     printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
  492.         fs->min_bounds.lbearing, fs->min_bounds.rbearing,
  493.         fs->min_bounds.width, fs->min_bounds.ascent,
  494.         fs->min_bounds.descent, fs->min_bounds.attributes);
  495.     printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
  496.         fs->max_bounds.lbearing, fs->max_bounds.rbearing,
  497.         fs->max_bounds.width, fs->max_bounds.ascent,
  498.         fs->max_bounds.descent, fs->max_bounds.attributes);
  499.     printf("per_char = 0x%x\n", fs->per_char);
  500.     printf("Text: (max) width = %d, height = %d\n",
  501.         wp->map_information->char_width, wp->map_information->char_height);
  502. #endif
  503.  
  504.     if (fs->min_bounds.width != fs->max_bounds.width)
  505.     X11_raw_print("Warning:  map font is not monospaced!");
  506. }
  507.  
  508. /*
  509.  * keyhit buffer
  510.  */
  511. #define INBUF_SIZE 64
  512. int inbuf[INBUF_SIZE];
  513. int incount = 0;
  514. int inptr = 0;    /* points to valid data */
  515.  
  516.  
  517. void
  518. extern_map_input(event)
  519.     XEvent *event;
  520. {
  521.     if(event->type == KeyPress)
  522.     map_input(window_list[WIN_MAP].w, (XtPointer) 0, (XtPointer) event);
  523. }
  524.  
  525. /*
  526.  * Keyboard and button event handler for map window.
  527.  */
  528. /* ARGSUSED */
  529. static void
  530. map_input(w, client_data, call_data)
  531.     Widget w;
  532.     XtPointer client_data, call_data;
  533. {
  534.     XEvent *event = (XEvent *) call_data;
  535.     XKeyEvent *key;
  536.     XButtonEvent *button;
  537.     int i, nbytes;
  538.     char c;
  539.     char keystring[MAX_KEY_STRING];
  540.  
  541.     switch (event->type) {
  542.     case ButtonPress:
  543.         button = (XButtonEvent *) event;
  544. #ifdef VERBOSE_INPUT
  545.         printf("button press\n");
  546. #endif
  547.         set_button_values(w, button->x, button->y, button->button);
  548.         break;
  549.     case KeyPress:
  550. #ifdef VERBOSE_INPUT
  551.         printf("key: ");
  552. #endif
  553.         if(appResources.slow && input_func) {
  554.         (*input_func)(w, event, NULL, NULL);
  555.         break;
  556.         }
  557.  
  558.         /*
  559.          * Don't use key_event_to_char() because we want to be able
  560.          * to allow keys mapped to multiple characters.
  561.          */
  562.         key = (XKeyEvent *) event;
  563.         nbytes = XLookupString(key, keystring, MAX_KEY_STRING, NULL, NULL);
  564.         /* Modifier keys return a zero length string when pressed. */
  565.         if (nbytes) {
  566. #ifdef VERBOSE_INPUT
  567.         printf("\"");
  568. #endif
  569.         for (i = 0; i < nbytes; i++) {
  570.             c = keystring[i];
  571.  
  572.             if (incount < INBUF_SIZE) {
  573.             inbuf[(inptr+incount)%INBUF_SIZE] =
  574.                 ((int) c) + ((key->state & Mod1Mask) ? 0x80 : 0);
  575.             incount++;
  576.             } else {
  577.             X11_nhbell();
  578.             }
  579. #ifdef VERBOSE_INPUT
  580.             /*
  581.              * Assume that mod1 is really the meta key.
  582.              */
  583.             if (key->state & Mod1Mask)    /* meta will print as M<c> */
  584.             (void) putchar('M');
  585.             if (c < ' ') {        /* ctrl will print as ^<c> */
  586.             (void) putchar('^');
  587.             c += '@';
  588.             }
  589.             (void) putchar(c);
  590. #endif
  591.         }
  592. #ifdef VERBOSE_INPUT
  593.         printf("\" [%d bytes]\n", nbytes);
  594. #endif
  595.         }
  596.         break;
  597.  
  598.     default:
  599.         impossible("unexpected X event, type = %d\n", (int) event->type);
  600.         break;
  601.     }
  602. }
  603.  
  604. static void
  605. set_button_values(w, x, y, button)
  606.     Widget w;
  607.     int x;
  608.     int y;
  609.     unsigned int button;
  610. {
  611.     struct xwindow *wp;
  612.     struct map_info_t *map_info;
  613.  
  614.     wp = find_widget(w);
  615.     map_info = wp->map_information;
  616.  
  617.     click_x = x / map_info->char_width;
  618.     click_y = y / map_info->char_height;
  619.  
  620.     /* The values can be out of range if the map window has been resized */
  621.     /* to be larger than the max size.                     */
  622.     if (click_x >= COLNO) click_x = COLNO-1;
  623.     if (click_y >= ROWNO) click_x = ROWNO-1;
  624.  
  625.     /* Map all buttons but the first to the second click */
  626.     click_button = (button == Button1) ? CLICK_1 : CLICK_2;
  627. }
  628.  
  629. /*
  630.  * Map window expose callback.
  631.  */
  632. static void
  633. map_exposed(w, event)
  634.     Widget w;
  635.     XExposeEvent *event;
  636. {
  637.     int x, y;
  638.     struct xwindow *wp;
  639.     struct map_info_t *map_info;
  640.     unsigned width, height;
  641.     int start_row, stop_row, start_col, stop_col;
  642.  
  643.     if (!XtIsRealized(w)) return;
  644.  
  645.     wp = find_widget(w);
  646.     map_info = wp->map_information;
  647.     /*
  648.      * The map is sent an expose event when the viewport resizes.  Make sure
  649.      * that the cursor is still in the viewport after the resize.
  650.      */
  651.     map_check_size_change(wp);
  652.  
  653.     if (event) {        /* called from button-event */
  654.     x      = event->x;
  655.     y      = event->y;
  656.     width  = event->width;
  657.     height = event->height;
  658.     } else {
  659.     x     = 0;
  660.     y     = 0;
  661.     width = wp->pixel_width;
  662.     height= wp->pixel_height;
  663.     }
  664.     /*
  665.      * Convert pixels into INCLUSIVE text rows and columns.
  666.      */
  667.     start_row = y / map_info->char_height;
  668.     stop_row = start_row + (height / map_info->char_height) +
  669.             (((height % map_info->char_height) == 0) ? 0 : 1) - 1;
  670.  
  671.     start_col = x / map_info->char_width;
  672.     stop_col = start_col + (width / map_info->char_width) +
  673.             (((width % map_info->char_width) == 0) ? 0 : 1) - 1;
  674.  
  675. #ifdef VERBOSE
  676.     printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n",
  677.                             x, y, width, height);
  678. #endif
  679.  
  680.     /* Out of range values are possible if the map window is resized to be */
  681.     /* bigger than the largest expected value.                   */
  682.     if (stop_row >= ROWNO) stop_row = ROWNO-1;
  683.     if (stop_col >= COLNO) stop_col = COLNO-1;
  684.  
  685.     map_update(wp, start_row, stop_row, start_col, stop_col, FALSE);
  686.     display_cursor(wp);        /* make sure cursor shows up */
  687. }
  688.  
  689. /*
  690.  * Do the actual work of the putting characters onto our X window.  This
  691.  * is called from the expose event routine, the display window (flush)
  692.  * routine, and the display cursor routine.  The later is a kludge that
  693.  * involves the inverted parameter of this function.  A better solution
  694.  * would be to double the color count, with any color above MAXCOLORS
  695.  * being inverted.
  696.  *
  697.  * This works for rectangular regions (this includes one line rectangles).
  698.  * The start and stop columns are *inclusive*.
  699.  */
  700. static void
  701. map_update(wp, start_row, stop_row, start_col, stop_col, inverted)
  702.     struct xwindow *wp;
  703.     int start_row, stop_row, start_col, stop_col;
  704.     boolean inverted;
  705. {
  706.     int win_start_row, win_start_col;
  707.     struct map_info_t *map_info = wp->map_information;
  708.     int row;
  709.     register int count;
  710.  
  711.     if (start_row < 0 || stop_row >= ROWNO) {
  712.     impossible("map_update:  bad row range %d-%d\n", start_row, stop_row);
  713.     return;
  714.     }
  715.     if (start_col < 0 || stop_col >=COLNO) {
  716.     impossible("map_update:  bad col range %d-%d\n", start_col, stop_col);
  717.     return;
  718.     }
  719.  
  720. #ifdef VERBOSE_UPDATE
  721.     printf("update: [0x%x] %d %d %d %d\n", 
  722.         (int) wp->w, start_row, stop_row, start_col, stop_col);
  723. #endif
  724.     win_start_row = start_row;
  725.     win_start_col = start_col;
  726.  
  727. #ifdef TEXTCOLOR
  728.     if (flags.use_color) {
  729.     register char *c_ptr;
  730.     char *t_ptr;
  731.     int cur_col, color, win_ystart;
  732.  
  733.     for (row = start_row; row <= stop_row; row++) {
  734.         win_ystart = map_info->char_ascent +
  735.                     (row * map_info->char_height);
  736.  
  737.         t_ptr = (char *) &(map_info->text[row][start_col]);
  738.         c_ptr = (char *) &(map_info->colors[row][start_col]);
  739.         cur_col = start_col;
  740.         while (cur_col <= stop_col) {
  741.         color = *c_ptr++;
  742.         count = 1;
  743.         while ((cur_col + count) <= stop_col && *c_ptr == color) {
  744.             count++;
  745.             c_ptr++;
  746.         }
  747.  
  748.         XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
  749.             inverted ? map_info->inv_color_gcs[color] :
  750.                    map_info->color_gcs[color],
  751.             map_info->char_lbearing + (map_info->char_width * cur_col),
  752.             win_ystart,
  753.             t_ptr, count);
  754.  
  755.         /* move text pointer and column count */
  756.         t_ptr += count;
  757.         cur_col += count;
  758.         } /* col loop */
  759.     } /* row loop */
  760.     } else
  761. #endif /* TEXTCOLOR */
  762.     {
  763.     int win_row, win_xstart;
  764.  
  765.     /* We always start at the same x window position and have    */
  766.     /* the same character count.                    */
  767.     win_xstart = map_info->char_lbearing +
  768.                     (win_start_col * map_info->char_width);
  769.     count = stop_col - start_col + 1;
  770.  
  771.     for (row = start_row, win_row = win_start_row;
  772.                     row <= stop_row; row++, win_row++) {
  773.  
  774.         XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
  775.         inverted ? map_info->inv_copy_gc : map_info->copy_gc,
  776.         win_xstart,
  777.         map_info->char_ascent + (win_row * map_info->char_height),
  778.         (char *) &(map_info->text[row][start_col]), count);
  779.     }
  780.     }
  781. }
  782.  
  783. /* Adjust the number of rows and columns on the given map window */
  784. void
  785. set_map_size(wp, cols, rows)
  786.     struct xwindow *wp;
  787.     Dimension cols, rows;
  788. {
  789.     Arg args[4];
  790.     Cardinal num_args;
  791.  
  792.     wp->pixel_width  = wp->map_information->char_width  * cols;
  793.     wp->pixel_height = wp->map_information->char_height * rows;
  794.  
  795.     num_args = 0;
  796.     XtSetArg(args[num_args], XtNwidth, wp->pixel_width);   num_args++;
  797.     XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
  798.     XtSetValues(wp->w, args, num_args);
  799. }
  800.  
  801. /*
  802.  * The map window creation routine.
  803.  */
  804. void
  805. create_map_window(wp, create_popup, parent)
  806.     struct xwindow *wp;
  807.     boolean create_popup;    /* parent is a popup shell that we create */
  808.     Widget parent;
  809. {
  810.     struct map_info_t *map_info;    /* map info pointer */
  811.     Widget map, viewport;
  812.     Arg args[10];
  813.     Cardinal num_args;
  814.     Dimension rows, columns;
  815.  
  816.     wp->type = NHW_MAP;
  817.  
  818.     map_info = wp->map_information =
  819.             (struct map_info_t *) alloc(sizeof(struct map_info_t));
  820.  
  821.     map_info->viewport_width = map_info->viewport_height = 0;
  822.     (void) memset((genericptr_t) map_info->text, ' ', sizeof(map_info->text));
  823.     (void) memset((genericptr_t) map_info->t_start, (char) COLNO,
  824.             sizeof(map_info->t_start));
  825.     (void) memset((genericptr_t) map_info->t_stop, (char) 0,
  826.             sizeof(map_info->t_stop));
  827. #ifdef TEXTCOLOR
  828.     (void) memset((genericptr_t) map_info->colors, NO_COLOR,
  829.             sizeof(map_info->colors));
  830. #endif
  831.  
  832.     if (create_popup) {
  833.     /*
  834.      * Create a popup that accepts key and button events.
  835.      */
  836.     num_args = 0;
  837.     XtSetArg(args[num_args], XtNinput, False);            num_args++;
  838.  
  839.     wp->popup = parent = XtCreatePopupShell("nethack",
  840.                     topLevelShellWidgetClass,
  841.                        toplevel, args, num_args);
  842.     }
  843.  
  844.     num_args = 0;
  845.     XtSetArg(args[num_args], XtNallowHoriz, True);    num_args++;
  846.     XtSetArg(args[num_args], XtNallowVert,  True);    num_args++;
  847.     /* XtSetArg(args[num_args], XtNforceBars,  True);    num_args++; */
  848.     XtSetArg(args[num_args], XtNuseBottom,  True);    num_args++;
  849.     viewport = XtCreateManagedWidget(
  850.             "map_viewport",        /* name */
  851.             viewportWidgetClass,    /* widget class from Window.h */
  852.             parent,            /* parent widget */
  853.             args,            /* set some values */
  854.             num_args);        /* number of values to set */
  855.  
  856.     /*
  857.      * Create a map window.  We need to set the width and height to some
  858.      * value when we create it.  We will change it to the value we want
  859.      * later
  860.      */
  861.     num_args = 0;
  862.     XtSetArg(args[num_args], XtNwidth,  100); num_args++;
  863.     XtSetArg(args[num_args], XtNheight, 100); num_args++;
  864.  
  865.     wp->w = map = XtCreateManagedWidget(
  866.         "map",            /* name */
  867.         windowWidgetClass,    /* widget class from Window.h */
  868.         viewport,        /* parent widget */
  869.         args,            /* set some values */
  870.         num_args);        /* number of values to set */
  871.  
  872.     XtAddCallback(map, XtNcallback,      map_input,      (XtPointer) 0);
  873.     XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
  874.  
  875.     get_char_info(wp);
  876.     get_gc(wp, WindowFont(map));
  877.  
  878.     /*
  879.      * Initially, set the map widget to be the size specified by the
  880.      * widget rows and columns resources.  We need to do this to
  881.      * correctly set the viewport window size.  After the viewport is
  882.      * realized, then the map can resize to its normal size.
  883.      */
  884.     num_args = 0;
  885.     XtSetArg(args[num_args], XtNrows,    &rows);    num_args++;
  886.     XtSetArg(args[num_args], XtNcolumns, &columns);    num_args++;
  887.     XtGetValues(wp->w, args, num_args);
  888.  
  889.     /* Don't bother with windows larger than ROWNOxCOLNO. */
  890.     if (columns > COLNO) columns = COLNO;
  891.     if (rows    > ROWNO) rows = ROWNO;
  892.  
  893.     set_map_size(wp, columns, rows);
  894.  
  895.     /*
  896.      * If we have created our own popup, then realize it so that the
  897.      * viewport is also realized.  Then resize the map window.
  898.      */
  899.     if (create_popup) {
  900.     XtRealizeWidget(wp->popup);
  901.     set_map_size(wp, COLNO, ROWNO);
  902.     }
  903. }
  904.  
  905. /*
  906.  * Destroy this map window.
  907.  */
  908. void
  909. destroy_map_window(wp)
  910.     struct xwindow *wp;
  911. {
  912.     struct map_info_t *map_info = wp->map_information;
  913. #ifdef TEXTCOLOR
  914.     int i;
  915. #endif
  916.  
  917.     if (wp->popup) {
  918.     nh_XtPopdown(wp->popup);
  919.  
  920.     /* Free allocated GCs. */
  921. #ifdef TEXTCOLOR
  922.     for (i = 0; i < MAXCOLORS; i++) {
  923.         XtReleaseGC(wp->w, map_info->color_gcs[i]);
  924.         XtReleaseGC(wp->w, map_info->inv_color_gcs[i]);
  925.     }
  926. #else
  927.     XtReleaseGC(wp->w, map_info->copy_gc);
  928.     XtReleaseGC(wp->w, map_info->inv_copy_gc);
  929. #endif
  930.  
  931.     /* Free malloc'ed space. */
  932.     free((char *) map_info);
  933.  
  934.     /* Destroy map widget. */
  935.     XtDestroyWidget(wp->popup);
  936.     }
  937.  
  938.     wp->type = NHW_NONE;    /* allow re-use */
  939. }
  940.  
  941.  
  942.  
  943. boolean exit_x_event;    /* exit condition for the event loop */
  944. /*******
  945. pkey(k)
  946.     int k;
  947. {
  948.     printf("key = '%s%c'\n", (k<32) ? "^":"", (k<32) ? '@'+k : k);
  949. }
  950. ******/
  951.  
  952. /*
  953.  * Main X event loop.  Here we accept and dispatch X events.  We only exit
  954.  * under certain circumstances.
  955.  */
  956. int
  957. x_event(exit_condition)
  958.     int exit_condition;
  959. {
  960.     XEvent  event;
  961.     int     retval;
  962.     boolean keep_going = TRUE;
  963.  
  964. #ifdef GCC_WARN
  965.     retval = 0;
  966. #endif
  967.  
  968.     click_button = NO_CLICK;    /* reset click exit condition */
  969.     exit_x_event = FALSE;    /* reset callback exit condition */
  970.  
  971.     /*
  972.      * Loop until we get a sent event, callback exit, or are accepting key
  973.      * press and button press events and we receive one.
  974.      */
  975.     if((exit_condition == EXIT_ON_KEY_PRESS ||
  976.     exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount)
  977.     goto try_test;
  978.  
  979.     do {
  980.     XtAppNextEvent(app_context, &event);
  981.     XtDispatchEvent(&event);
  982.  
  983.     /* See if we can exit. */
  984.     try_test:
  985.     switch (exit_condition) {
  986.         case EXIT_ON_SENT_EVENT: {
  987.         XAnyEvent *any = (XAnyEvent *) &event;
  988.         if (any->send_event) {
  989.             retval = 0;
  990.             keep_going = FALSE;
  991.         }
  992.         break;
  993.         }
  994.         case EXIT_ON_EXIT:
  995.         if (exit_x_event) {
  996.             incount = 0;
  997.             retval = 0;
  998.             keep_going = FALSE;
  999.         }
  1000.         break;
  1001.         case EXIT_ON_KEY_PRESS:
  1002.         if (incount != 0) {
  1003.             /* get first pressed key */
  1004.             --incount;
  1005.             retval = inbuf[inptr];
  1006.             inptr = (inptr+1) % INBUF_SIZE;
  1007.             /* pkey(retval); */
  1008.             keep_going = FALSE;
  1009.         }
  1010.         break;
  1011.         case EXIT_ON_KEY_OR_BUTTON_PRESS:
  1012.         if (incount != 0 || click_button != NO_CLICK) {
  1013.             if (click_button != NO_CLICK) {    /* button press */
  1014.             /* click values are already set */
  1015.             retval = 0;
  1016.             } else {                /* key press */
  1017.             /* get first pressed key */
  1018.             --incount;
  1019.             retval = inbuf[inptr];
  1020.             inptr = (inptr+1) % INBUF_SIZE;
  1021.             /* pkey(retval); */
  1022.             }
  1023.             keep_going = FALSE;
  1024.         }
  1025.         break;
  1026.         default:
  1027.         panic("x_event: unknown exit condition %d\n", exit_condition);
  1028.         break;
  1029.     }
  1030.     } while (keep_going);
  1031.  
  1032.     return retval;
  1033. }
  1034.  
  1035. /*winmap.c*/
  1036.